use std::sync::Arc;

use deno_core::{op2, v8, OpState};
use thunderdome::Index;
use QcCore::{
    resources::ResourceManager,
    scene_system::{scene::Scene, scene_manager::SceneManager},
};
use QcTools::utils::r#ref::Ref;

use crate::utils::GoExt;

#[op2]
pub fn opLoadSceneFromName<'a>(
    state: &mut OpState,
    scope: &mut v8::HandleScope<'a>,
    #[string] name: &str,
) -> v8::Local<'a, v8::Value> {
    let resource_manager = state.borrow::<Arc<ResourceManager>>();

    let res = resource_manager.get(name);

    if let Some(ref res) = res {
        let text = String::from_utf8(res.file.data.to_vec()).unwrap();
        let scene = Scene::load(&text, resource_manager.clone());

        let scene_manager = state.borrow_mut::<Ref<SceneManager>>();
        let mut scene_manager = scene_manager.try_write().unwrap();
        let index = scene_manager.load_scene(scene);
        let obj = v8::Object::new(scope);
        let key = v8::String::new(scope, "uuid").unwrap();
        let value = v8::Number::new(scope, index.to_bits() as _);

        obj.set(scope, key.into(), value.into());

        GoExt::set_prototype(scope, obj, "Scene");

        return obj.into();
    }

    return v8::undefined(scope).into();
}

#[op2]
pub fn opLoadScene<'a>(
    state: &mut OpState,
    scope: &mut v8::HandleScope<'a>,
    scene: v8::Local<v8::Object>,
) -> v8::Local<'a, v8::Value> {
    let key = v8::String::new(scope, "uuid").unwrap();

    let index = scene.get(scope, key.into()).unwrap();
    let index = v8::Local::<v8::Number>::try_from(index).unwrap();
    let index = index.value() as u64;
    let index = Index::from_bits(index).unwrap();

    let scene_manager = state.borrow_mut::<Ref<SceneManager>>();
    let mut scene_manager = scene_manager.try_write().unwrap();
    scene_manager.load_scene_from_index(index);

    return v8::undefined(scope).into();
}

#[op2]
pub fn opPreloadScene<'a>(
    state: &mut OpState,
    scope: &mut v8::HandleScope<'a>,
    #[string] name: &str,
) -> v8::Local<'a, v8::Value> {
    let resource_manager = state.borrow::<Arc<ResourceManager>>();

    let res = resource_manager.get(name);

    if let Some(ref res) = res {
        let text = String::from_utf8(res.file.data.to_vec()).unwrap();
        let scene = Scene::load(&text, resource_manager.clone());

        let scene_manager = state.borrow_mut::<Ref<SceneManager>>();
        let mut scene_manager = scene_manager.try_write().unwrap();
        let index = scene_manager.preload_scene(scene);
        let obj = v8::Object::new(scope);
        let key = v8::String::new(scope, "uuid").unwrap();
        let value = v8::Number::new(scope, index.to_bits() as _);

        obj.set(scope, key.into(), value.into());

        GoExt::set_prototype(scope, obj, "Scene");

        return obj.into();
    }

    return v8::undefined(scope).into();
}
